﻿using Core.Tools.Cache;
using Hardware.Reactor.Base;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using UI.Application.Reactor.Helper;
using UI.Application.Reactor.Services;
using UI.Application.Share.Config;
using UI.Application.Share.Reactor;

namespace UI.Application.Reactor.Models
{
    /// <summary>
    /// 反应釜的业务实体
    /// </summary>
    public class ReactorModel : ReactiveObject, IReactorModel
    {
        /// <summary>
        /// 温度采集模块
        /// </summary>
        [Reactive]
        public ITempReader TempReader { get;private set; }
        [Reactive]
        public ReactorName ReactorName { get; set; }
        /// <summary>
        /// 反应釜运行流程的参数集合
        /// </summary>
        [Reactive]
        public ObservableCollection<ReactorParameter> Parameters { get; set; }=new ObservableCollection<ReactorParameter>();
        /// <summary>
        /// 执行的流程总量
        /// </summary>
        [Reactive]
        public int FlowCount { get; private set; }
        /// <summary>
        /// 正在执行的第几个流程
        /// </summary>
        [Reactive]
        public int RunningIndex { get; private set; }
        /// <summary>
        /// 正在运行的第几个流程的文本
        /// </summary>
        [Reactive]
        public string RunningInfo { get;private set; }
        /// <summary>
        /// 已运行多少时间
        /// </summary>
        [Reactive]
        public string RunningTime { get;private set; }
        /// <summary>
        /// 总运行多少时间
        /// </summary>
        [Reactive]
        public string SumRunningTime { get; private set; }
        /// <summary>
        /// 是否运行中
        /// </summary>
        [Reactive]
        public bool IsRunning { get; private set; }
        /// <summary>
        /// 是否中止运行
        /// </summary>
        [Reactive]
        public bool IsCancel { get; private set; }
        [Reactive]
        public string Message { get; set; }
        /// <summary>
        /// 运行消息
        /// </summary>
        [Reactive]
        public ObservableCollection<string> MessageList { get; set; } = new ObservableCollection<string>();

        private ICacheManager CacheManager { get; }
        private IPidProvider PidProvider { get; }
        private IReactorCommandManager ReactorCommandManager { get; }
        private ITempController TempController { get; }

        public ICommand AddParameterCommand { get; }
        public ICommand RemoveParameterCommand { get; }
        public ICommand StartTaskCommand { get; }
        public ICommand StopTaskCommand { get; }

        public ReactorModel(
            ReactorName reactorName,
            ITempReader tempReader,
            ICacheManager cacheManager,
            IPidProvider pidProvider,
            IReactorCommandFactory reactorCommandFactory,
            ITempController tempController
            )
        {
            ReactorName = reactorName;
            TempReader = tempReader;
            CacheManager = cacheManager;
            PidProvider = pidProvider;
            ReactorCommandManager = reactorCommandFactory.CreateReactorCommandManager(reactorName);//当前反应釜的指令生成管理器
            TempController = tempController;//温度控制器模块（加热制冷）

            AddParameterCommand = ReactiveCommand.Create(AddParameter);
            RemoveParameterCommand = ReactiveCommand.Create<ReactorParameter>(RemoveParameter);
            StartTaskCommand = ReactiveCommand.CreateFromTask(RunAsync);//开始反应釜的加热制冷工作
            StopTaskCommand = ReactiveCommand.Create(() => IsCancel = true);//停止反应釜的工作

            LoadParameter();

            this.WhenAnyValue(p => p.Parameters, p => p.Parameters.Count).Subscribe(p => SaveParameter());
            this.WhenAnyValue(p => p.Message).ObserveOn(RxApp.MainThreadScheduler).Subscribe(message => MessageList.Insert(0, message));

        }

        private async Task RunAsync()
        {
            if (Parameters.Count == 0) return;

            IsCancel = false;
            IsRunning = true;
            RunningIndex= 0;
            RunningTime = string.Empty;
            RunningInfo = string.Empty;
            SumRunningTime = string.Empty;

            Stopwatch totolwatch=Stopwatch.StartNew();//总计时器
            
            foreach (ReactorParameter p in Parameters)
            {                
                //加热制冷处理 -> 温度控制器
                RunningIndex++;
                RunningInfo = $"{RunningIndex}/";
                p.ReactorState = ReactorState.Running;
                Stopwatch stopwatch = Stopwatch.StartNew();
                while (stopwatch.ElapsedMilliseconds < p.Minute * 60 * 1000)
                {
                    //每10秒下发一次指令
                    if (stopwatch.ElapsedMilliseconds / 1000 % 10 == 0)
                    {
                        //设置目标值和反馈值
                        double target = p.RTTarget;
                        //实际温度
                        double feedback = TempReader.Temperature.RT;
                        //是否开启RT速率
                        if (p.IsRTSpeed && stopwatch.ElapsedMilliseconds / 1000 % 60 == 0)
                        {
                            feedback += p.RTSpeed;
                            Message = $"[{DateTime.Now}]加入RT速率值：{p.RTSpeed}";
                        }

                        if(target - feedback > 0)
                        {
                            //说明需要加热

                            var pid = PidProvider.GetHeatPID(ReactorName);                            
                            var pidController = new PIDController(pid.P, pid.I, pid.D, 0, 4000);
                            //时间间隔
                            double deltaTime = 0.1;
                            //计算PID值
                            double v = pidController.Calculate(target, feedback, deltaTime);
                            //停止制冷 
                            Stop(TemperatureMode.停止制冷);
                            var commandBytes = ReactorCommandManager.GetHeatByte((ushort)v);
                            TempController.Send(commandBytes);
                            Message = $"[{DateTime.Now}]加热，写入PID值：{v}={pid.P},{pid.I},{pid.D}";
                        }
                        else
                        {
                            //说明需要制冷 
                            var pid = PidProvider.GetPeltierPID(ReactorName);//获取制冷PID参数
                            //计算当前温度与PID参数
                            var pidController = new PIDController(pid.P, pid.I, pid.D, 0, 1000);
                            //时间间隔
                            double deltaTime = 0.5;
                            //计算PID值
                            double v = pidController.Calculate(target, feedback, deltaTime);

                            Stop(TemperatureMode.停止加热);//停止加热

                            if (feedback <= 40)
                            {
                                var commandBytes = ReactorCommandManager.GetCoolByte((ushort)v);
                                TempController.Send(commandBytes);//开始制冷 
                                Message = $"[{DateTime.Now}]制冷 ，写入PID值：{v}={pid.P},{pid.I},{pid.D}";

                            }
                        }
                    }

                    if (IsCancel)
                    {
                        p.ReactorState = ReactorState.Cancel;
                        break;
                    }

                    RunningTime = "当前 " + stopwatch.Elapsed.ToString(@"hh\:mm\:ss");
                    SumRunningTime = "总计 " + totolwatch.Elapsed.ToString(@"hh\:mm\:ss");

                    await Task.Delay(1000);
                }
                p.ReactorState = p.ReactorState != ReactorState.Cancel ? ReactorState.Completed : ReactorState.Cancel;
                if(IsCancel) break;
            }
        }

        /// <summary>
        /// 加载反庆釜参数的本地缓存
        /// </summary>
        private void LoadParameter()
        {
            if(CacheManager.Get(ReactorName,out ObservableCollection<ReactorParameter> param))
            {
                Parameters = param;
                foreach (var item in Parameters)
                {
                    item.ReactorState = ReactorState.None;
                }
            }
        }

        /// <summary>
        /// 保存反应釜的流程参数到本地
        /// </summary>
        private void SaveParameter()
        {
            CacheManager.Set(ReactorName, Parameters);
            FlowCount= Parameters.Count();
        }
        private void RemoveParameter(ReactorParameter parameter)
        {
            Parameters.Remove(parameter);
        }

        private void AddParameter()
        {
            Parameters.Add(new ReactorParameter());
        }

        /// <summary>
        /// 停止加冷或停止制冷
        /// </summary>
        /// <param name="mode"></param>
        private void Stop(TemperatureMode? mode = null)
        {
            var stopHeat = ReactorCommandManager.GetHeatByte(0);//停止加热指令
            var stopCool = ReactorCommandManager.GetCoolByte(0);//停止制冷指令
            if(mode == null)
            {
                TempController.Send(stopHeat);
                TempController.Send(stopCool);
            }
            else
            {
                if(mode == TemperatureMode.停止加热)
                {
                    TempController.Send(stopHeat);
                }
                else
                {
                    TempController.Send(stopCool);
                }
            }
        }
    }
}
